package com.jbm.core.common;

import com.jbm.core.client.MainCallback;
import com.jbm.core.iface.IAcross;
import com.jbm.core.iface.IFileObject;
import com.jbm.core.iface.IP2P;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.logging.LogLevel;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.Random;
import java.util.concurrent.Executors;

/**
 * Created by root on 17-3-22.
 */
public abstract class MainServer
{
	protected static Logger logger = LoggerFactory.getLogger(MainServer.class);
	public static final char Server_type_Server = 0;
	public static final char Server_type_Client = 1;

	private static MainServer g_server;

	public static MainServer getG_server()
	{
		return g_server;
	}
	public static void setG_server ( MainServer g_server )
	{
		MainServer.g_server = g_server;
	}
//	public static P2PServer g_p2pserver = null;

	protected MainCallback m_maincallback;
	private Integer m_local_id;
	private String m_app_type;

	protected char m_server_type;

	protected int m_localport;

	private IoAcceptor m_acceptor;

	public String getM_temppath()
	{
		return m_temppath;
	}

	public void setM_temppath(String m_temppath)
	{
		this.m_temppath = m_temppath;
	}

	private String m_temppath;

	private boolean m_cli_log_init;
	private boolean m_cli_callback_init;
	private boolean m_cli_AC_init;
	private boolean m_cli_localport_init;
	private boolean m_cli_localid_init;
	private boolean m_cli_AccCtrl_init;
	private boolean m_AccCtrlCAQ_init;
	private boolean m_cli_ASCA_init;
	private boolean m_cli_ASCAConnect_init;

	public MainServer()
	{
		m_temppath = null;
		m_cli_log_init = false;
		m_cli_callback_init = false;
		m_cli_AC_init = false;
		m_cli_localport_init = false;
		m_cli_localid_init = false;
		m_cli_AccCtrl_init = false;
		m_AccCtrlCAQ_init = false;
		m_cli_ASCA_init = false;
		m_cli_ASCAConnect_init = false;
	}

	public boolean Init(String config,
	                 String serverhost,
	                 int serverport,
	                 String app_type,
	                 MainCallback callback )
	{
		m_app_type = app_type;

		if ( app_type.equals("app_server"))
		{
			m_server_type = Server_type_Server;

			MessageQueue.g_mq.Init(10000,1);
			SysLog.g_syslog.Init("jbm_syslog.log",31,31);

			AutoCall.g_autocall.InitAC(10000,
					"IP2P.Match|keepalive.|1st.|" +
							"IRegister.Register|" +
							"IAccCtrl.GetAccList|"+
							"IAplipay.CheckResult|"+
							"IAplipay.checkResultWX|"+
							"IWeather.getinfo|"+
					        "ClickTimesEntity.add|"+

							"GeoInfoEntity.getlist|"+
							"IAppVersion.confirm|"+
							"IDownloadMedia.downMedia|"+
							"IGeoinfo.getlist|"+
							"ILogin.login|"+
							"InfomationEntity.GetInfoList|"+
							"InfomationEntity.GetInfoListBySearch|"+
							"InfomationEntity.GetInfoListByLogin|"+
							"InfomationEntity.GetBusInfoListBySearch|"+
							"IRegistCustomer.reg_new|"+
							"IRegistCustomer.bind_all|"+
							"ISaleActivity.load|"+
							"IVerifyCode.create|"+
							"LoginEntity.wxlogin|"+
							"LoginEntity.loginm"

					,
					"com.jbm.core" +
							"|com.jbm.onehome",
					"com.jbm.core.client|" +
							"com.jbm.onehome.client",
					"com.jbm.core.server|" +
							"com.jbm.onehome");

			m_localport = serverport;
			m_maincallback = null;
			m_local_id = AccountCtrl.Account_Server_id;

			AccountCtrl.g_accountctrl.InitAccountqueue(20000);

			try
			{
				m_acceptor = new NioSocketAcceptor();
				// 设置过滤器
				LoggingFilter lf = new LoggingFilter();
				lf.setMessageSentLogLevel(LogLevel.NONE);
				m_acceptor.getFilterChain().addLast("logger", lf);
				m_acceptor.getFilterChain().addLast("codec",
						new ProtocolCodecFilter(new OHCodeFactory("UTF-8")));
				m_acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
				// 设置读取数据的缓冲区大小
				m_acceptor.getSessionConfig().setReadBufferSize(4096);
				// 读写通道10秒内无操作进入空闲状态
				m_acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);

				//Init HeartBeat
				KeepAliveMessageFactory kamf = new JBMKeepAliveMessageFactory(HBType.SERVER);
				KeepAliveFilter kaf = new KeepAliveFilter(kamf, IdleStatus.BOTH_IDLE);
				kaf.setForwardEvent(true);
				kaf.setRequestInterval(10);
				m_acceptor.getFilterChain().addLast("heart", kaf);

				// 绑定逻辑处理器
				m_acceptor.setHandler(new MainHandler());
				// 绑定端口
				m_acceptor.bind(new InetSocketAddress(m_localport));
				logger.info("服务端启动成功... 端口号为：" + m_localport);
			}catch (Exception e)
			{
				logger.error("服务端启动异常....", e);
				e.printStackTrace();
			}
		}else
		{
			m_server_type = Server_type_Client;

			if ( !m_cli_log_init )
			{
				SysLog.g_syslog.Init("jbm.log", 31, 31);
				m_cli_log_init = true;
			}

			if ( !m_cli_callback_init )
			{
				m_maincallback = callback;
				m_cli_callback_init = true;
			}

			if ( !m_cli_AC_init )
			{
				AutoCall.g_autocall.InitAC(1000,
						"IConnectAgent.PushCA|" +
								"IConnectAgent.OfflineCA|" +
								"IP2P.PushPoint",
						"com.jbm.core" +
								"|com.jbm.onehome",
						"com.jbm.core.client|" +
								"com.jbm.onehome.client", null);
				m_cli_AC_init = true;
			}

			if ( !m_cli_localport_init )
			{
				Random r = new Random();
				m_localport = (int) (r.nextInt(8000) + 2000);
				m_cli_localport_init = true;
			}

			if ( !m_cli_localid_init )
			{
				m_local_id = 0;
				m_cli_localid_init = true;
			}

			if ( !m_cli_AccCtrl_init )
			{
				AccountCtrl.g_accountctrl.InitAccountmap();
				m_cli_AccCtrl_init = true;
			}
		}

		if ( !m_AccCtrlCAQ_init )
		{
			AccountCtrl.g_accountctrl.InitCAqueue(2000);
			m_AccCtrlCAQ_init = true;
		}


		if ( m_server_type == Server_type_Client )
		{
			if ( !m_cli_ASCA_init )
			{
				ConnectAgent ca = new ConnectAgent("app_server", serverhost, serverport, m_localport, MainServer.Server_type_Client, 5000);

				AccountCtrl.g_accountctrl.PushPoint(AccountCtrl.Account_Server_id, ca);

				m_cli_ASCA_init = true;
			}

			if ( !m_cli_ASCAConnect_init )
				m_cli_ASCAConnect_init =  AccountCtrl.g_accountctrl.Connect2Server(AccountCtrl.Account_Server_id,"app_server");

			return m_cli_ASCAConnect_init;
		}

		return true;
	}

	public int getM_localport()
	{
		return m_localport;
	}

	public void setM_local_id ( Integer local_id )
	{
		m_local_id = local_id;
	}

	public Integer getM_local_id()
	{
		return m_local_id;
	}

	public String getM_app_type()
	{
		return m_app_type;
	}

	public char getM_server_type()
	{
		return m_server_type;
	}

	public MainCallback getM_maincallback()
	{
		return m_maincallback;
	}

	public IAcross SendText (Integer receiver, String app_type, String msg, ConnectAgent... param )
	{
		int acc_id = 0;

		if ( MainServer.getG_server().getM_server_type() == MainServer.Server_type_Server )
		{
			if (param.length > 0)
			{
				IAccount ia = param[0].getM_iaccount();

				if (ia != null)
					acc_id = ia.getM_account_id();
			}
		}else
			acc_id = MainServer.g_server.getM_local_id();

		return Remote(param, receiver, app_type,
				new IP2P( acc_id, receiver, msg, true), "PushPoint", true, true,false,true);
	}

	public IAcross SendFile ( int login_id, String app_type, String filepath, String filename, String filetype, ConnectAgent... param )
	{
		int acc_id = 0;

		if ( MainServer.getG_server().getM_server_type() == MainServer.Server_type_Server )
		{
			if (param.length > 0)
			{
				IAccount ia = param[0].getM_iaccount();

				if (ia != null)
					acc_id = ia.getM_account_id();
			}
		}else
			acc_id = MainServer.g_server.getM_local_id();

		return Remote(param, IP2P.class, login_id, app_type,
				new IP2P( acc_id, login_id,
				filepath,filename,filetype), "PushFile", true, true,true,true);
	}

	public IAcross uploadFile ( String filepath, String filename, ConnectAgent... param )
	{
		return Remote(param, IFileObject.class,AccountCtrl.Account_Server_id,"app_server",new IFileObject(filepath,filename),"upload",true,true,true,false);
	}

	public IAcross keepalive()
	{
		return AccountCtrl.g_accountctrl.keepalive(AccountCtrl.Account_Server_id,"app_server",true,true);
	}

	public IAcross Remote ( ConnectAgent[] param, Integer to_id, String app_type, IAcross content, String method, boolean hasresp, boolean waitresp, boolean excode, boolean intask )
	{
		if ( param.length > 0 )
			return AccountCtrl.g_accountctrl.SendPoint(param[0], to_id, app_type, null, method, content, hasresp, waitresp,excode,intask);
		else
			return AccountCtrl.g_accountctrl.SendPoint(null, to_id, app_type, null, method, content, hasresp, waitresp,excode,intask);
	}

	public IAcross Remote ( ConnectAgent[] param, Class<?> clz, Integer to_id, String app_type, IAcross content, String method, boolean hasresp, boolean waitresp )
	{
		return Remote ( param, clz, to_id, app_type, content, method, hasresp, waitresp, false, false );
	}

	public IAcross Remote ( ConnectAgent[] param, Class<?> clz, Integer to_id, String app_type, IAcross content, String method, boolean hasresp, boolean waitresp, boolean excode, boolean intask )
	{
		IAcross ia = Remote ( param, to_id, app_type, content, method, hasresp, waitresp, excode, intask );

		if ( clz.getSimpleName().equals("IAcross") )
			return ia;

		if ( ia.getClass().getSimpleName().equals("IAcross"))
		{
			IAcross rtn = null;
			try
			{
				rtn = (IAcross) clz.newInstance();
				rtn.m_code = ia.m_code;
				rtn.m_info = ia.m_info;
			}catch (Exception e)
			{
			}

			return rtn;
		}else
			return ia;
	}

	public abstract String login();
	public abstract boolean islogin();
	public abstract void cancellogin();
}
